package edu.ilstu.mind.ise.module.arduino.alias;

import java.util.HashMap;
import java.util.Map;

import edu.ilstu.mind.ise.module.arduino.controller.ArduinoController;
import edu.ilstu.mind.ise.module.arduino.controller.ArduinoException;
import edu.ilstu.mind.ise.module.arduino.controller.PinMode;

public class ArduinoAliasManager {

	private final Map<String, Pin> aliases = new HashMap<String, Pin>();
	private final ArduinoController controller;
	
	public ArduinoAliasManager(ArduinoController controller) {
		this.controller = controller;
	}
		
	public synchronized void createAlias(String pinId, String alias, PinMode pinMode) throws ArduinoException {
		if(!aliases.containsKey(alias)) {
			controller.setPinMode(pinId, pinMode);
			aliases.put(alias, new Pin(pinId, pinMode));
		} else {
			throw new IllegalArgumentException("Alias <" + alias + "> already exists!");
		}
	}
	
	public synchronized PinMode getPinMode(String alias) {
		Pin pin = aliases.get(alias);
		return pin != null ? pin.pinMode : null;
	}

	public void digitalWrite(String alias, boolean value) throws ArduinoException {
		String pinId = getPinId(alias, PinMode.DIGITAL_OUTPUT);
		controller.digitalWrite(pinId, value);
	}

	public void analogWrite(String alias, int value) throws ArduinoException {
		String pinId = getPinId(alias, PinMode.ANALOG_OUTPUT);
		controller.analogWrite(pinId, value);
	}

	public boolean digitalRead(String alias) throws ArduinoException {
		String pinId = getPinId(alias, PinMode.DIGITAL_INPUT);
		return controller.digitalRead(pinId);
	}

	public int analogRead(String alias) throws ArduinoException {
		String pinId = getPinId(alias, PinMode.ANALOG_INPUT);
		return controller.analogRead(pinId);
	}
	
	private synchronized String getPinId(String alias, PinMode expectedPinMode) throws ArduinoException {
		Pin pin = aliases.get(alias);
		if(pin == null) {
			throw new ArduinoException("Alias <" + alias + "> does not exist");
		} else if(pin.pinMode != expectedPinMode) {
			throw new ArduinoException("Alias <" + alias + "> pin mode is <" + pin.pinMode + "> but it is trying to be used as <" + expectedPinMode + ">");
		} else {
			return pin.pinId;
		}
	}

	private static class Pin {
		public final String pinId;
		public final PinMode pinMode;
		public Pin(String pinId, PinMode pinMode) {
			this.pinId = pinId;
			this.pinMode = pinMode;
		}
	}
}
